package wikiPhilia_two;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

import processing.core.PApplet;
import processing.core.PFont;
import processing.core.PVector;
import wpRelations.TsvTable;

public class WikiPhilia_two_001 {
	public HashMap<String, WNode> allNodes = new HashMap<String, WNode>();
	public ArrayList<WNode> allNodesList = new ArrayList<WNode>();
	public ArrayList<WNode> nodesLevelZeroList = new ArrayList<WNode>();
	public HashMap<String, WNode> nodesLevelZero = new HashMap<String, WNode>();
	public ArrayList<WNode> nodesLevelOneList = new ArrayList<WNode>();
	public HashMap<String, WNode> nodesLevelOne = new HashMap<String, WNode>();
	public ArrayList<WNode> nodesLevelTwoList = new ArrayList<WNode>();
	public HashMap<String, WNode> nodesLevelTwo = new HashMap<String, WNode>();
	public ArrayList<WEdge> allEdgesList = new ArrayList<WEdge>();
	PApplet p5;
	TsvTable inputTable;
	String personZeroTitle;
	//String inputFileName  = "Albert_Einstein_complete_stuff.tsv";
	String inputFileName;
	float minRadiusZero = 100f, maxRadiusZero = 200f,minRadiusOne = 200f, 
			maxRadiusOne = 400f;
	static float yAngle;
	static float xAngle;
	int loadSize = 3000;
	float interval = 1*30f; //in 30 fps
	int currentRow = 0;
	int maxLinkCount = -1;
	PFont myFont;
	float xOff, yOff, zOff;

	WikiPhilia_two_001(PApplet parent, String name, String fileName ) {
		 personZeroTitle = name;
		 inputFileName = fileName;
		p5 = parent;
	}

	public void setup() {
		inputTable = new TsvTable(p5, inputFileName);
		putNode(new WNode(p5, personZeroTitle), 0);
		nodesLevelZeroList.get(0).setType(WNode.TYPE_PERSON);
		nodesLevelZeroList.get(0).setPos(new PVector(0,0,0));
		System.out.println("The table " + inputFileName + " has "
				+ inputTable.getRowCount() + " rows.");
		System.out.println("The table " + inputFileName + " has "
				+ inputTable.data[0].length + " coloumns.");
		p5.noFill();
		p5.noStroke();
		myFont = p5.loadFont("data\\TheSerifSemiBold-Plain-48.vlw");
		p5.textFont(myFont,16);
		p5.textAlign(p5.CENTER);
		p5.textMode(p5.MODEL);
         xOff = 0;
         yOff = 0;


	}

	public void draw() {
		p5.background(0);
        p5.translate(xOff,yOff,zOff);
		p5.translate(p5.width/2,p5.height/2);
		xAngle = p5.map(p5.mouseY,0,p5.height,0,p5.TWO_PI);
		yAngle = p5.map(p5.mouseX,0,p5.width,0,p5.TWO_PI)+p5.PI;
		p5.rotateX(xAngle);
		p5.rotateY(yAngle);

		if (p5.frameCount % interval == 0) {
			addNodesEdges(inputTable, currentRow, currentRow+loadSize-1);
			currentRow += loadSize;
			setPositions(nodesLevelOneList, nodesLevelZeroList.get(0), minRadiusZero, maxRadiusZero, 300, 502);
			setPositions(nodesLevelTwoList, nodesLevelZeroList.get(0), minRadiusOne, maxRadiusOne, 300, 502);
			System.out.println("Nodes l0: " + nodesLevelZeroList.size());
			System.out.println("Nodes l1: " + nodesLevelOneList.size());
			System.out.println("Nodes l2: " + nodesLevelTwoList.size());
			System.out.println("Nodes alltogether: " + allNodesList.size());
			System.out.println("Edges alltogether: " + allEdgesList.size());
			System.out.println("Parsing line: " + currentRow + " out of: " + inputTable.getRowCount());
		}
		for (int i = 0; i < allNodesList.size(); i++) {
			allNodesList.get(i).update();
			//allNodesList.get(i).display();
			
		}
		for (int i = 0; i < nodesLevelOneList.size(); i++) {
			nodesLevelOneList.get(i).display();
		}
		for (int i = 0; i < nodesLevelTwoList.size(); i++) {
			nodesLevelTwoList.get(i).display();
		}
		for (int i = 0; i < allEdgesList.size(); i++) {
			//allEdgesList.get(i).display();
		}
	}

	public void setPositions(ArrayList<WNode> theNodes, WNode origin, float minR, float maxR, int hC, int vC) {
		int nodeCount = theNodes.size();
		float myInc = 1/(float)(nodeCount);
		//centerNode.setPos(new PVector(0,0,0));
		float hCycles = hC;
		float vCycles = vC;
		int originIndex;
		if (theNodes.contains(origin)) {
			originIndex= theNodes.indexOf(origin);
		} else {
			originIndex = -1;
		}
		for (int i = 0; i < nodeCount; i++) {
			if (i != originIndex) {
				float myRadius = minR - (theNodes.get(i).getLinksCount(3)/(float)maxLinkCount)*(maxR-minR);
				//float myRadius = maxR; ///just for testing purposes!
				float myIncH = myInc*i;
				float myIncV = myInc*i;
				float lambda = p5.TWO_PI*myInc*i*hCycles;
				float beta = p5.TWO_PI*myInc*i*vCycles;
				float x = origin.getcPos().x + p5.sin(lambda)*p5.cos(beta)*myRadius;
				float y = origin.getcPos().y + p5.sin(beta)*myRadius;
				float z = origin.getcPos().z + p5.cos(lambda)*p5.cos(beta)*myRadius;
				theNodes.get(i).setPos(new PVector(x,y,z));
			}
		}
		
	}

	
	public void addNodesEdges(TsvTable sourceTable, int startIndex, int endIndex) {
		for (int i = p5.min(sourceTable.getRowCount(), startIndex); i < p5.min(
				sourceTable.getRowCount(), endIndex); i++) {
			String fromTitle = inputTable.getString(i, 0);
			String toTitle = inputTable.getString(i, 1);
			String fromType = inputTable.getString(i, 2);
			String toType = inputTable.getString(i, 3);
			int iFromType = WNode.TYPE_ARTICLE;
			int iToType = WNode.TYPE_ARTICLE;
			if (fromType.equalsIgnoreCase("person"))
				iFromType = WNode.TYPE_PERSON;
			if (fromType.equalsIgnoreCase("non_person"))
				iFromType = WNode.TYPE_NON_PERSON;
			if (fromType.equalsIgnoreCase("category"))
				iFromType = WNode.TYPE_CATEGORY;
			if (toType.equalsIgnoreCase("person"))
				iToType = WNode.TYPE_PERSON;
			if (toType.equalsIgnoreCase("non_person"))
				iToType = WNode.TYPE_NON_PERSON;
			if (toType.equalsIgnoreCase("category"))
				iToType = WNode.TYPE_CATEGORY;
			WNode fromNode = new WNode(p5, fromTitle, iFromType);
			WNode toNode = new WNode(p5, toTitle, iToType);
			//TODO: loops!!!!
			if (nodesLevelZero.containsKey(fromTitle)) {
				if (!nodesLevelOne.containsKey(toTitle)) {
					putNode(toNode, 1);
					nodesLevelZero.get(fromTitle).incLinks(1);
					toNode.incBacklinks(1);
					allEdgesList.add(new WEdge(p5,nodesLevelZero.get(fromTitle),toNode));
				} else {
					// TODO: LOOP
				}
			} else if (nodesLevelOne.containsKey(fromTitle)) {
				if (!nodesLevelZero.containsKey(toTitle)) {
					if (!nodesLevelOne.containsKey(toTitle)) {
						if (!nodesLevelTwo.containsKey(toTitle)) {
							putNode(toNode,2);
							nodesLevelOne.get(fromTitle).incLinks(2);
							toNode.incBacklinks(1);
							allEdgesList.add(new WEdge(p5,nodesLevelOne.get(fromTitle),toNode));
						} else {
							
						}
						
					} else {
						// TODO: LOOP
					}
				} else {
					
				};
			} else if (nodesLevelTwo.containsKey(fromTitle)) {
				if (!nodesLevelOne.containsKey(toTitle)) {
					if (!nodesLevelTwo.containsKey(toTitle)) {
						putNode(toNode,2);
						nodesLevelTwo.get(fromTitle).incLinks(2);
						toNode.incBacklinks(2);
						allEdgesList.add(new WEdge(p5,nodesLevelTwo.get(fromTitle),toNode));
					} else {
						//System.out.println("ERROR ?!");
					}
				} else {
						
					}
			} else if  (nodesLevelZero.containsKey(toTitle)){
				if (!nodesLevelOne.containsKey(fromTitle)) {
					putNode(fromNode, 1);
					nodesLevelZero.get(toTitle).incLinks(1);
					fromNode.incBacklinks(1);
					allEdgesList.add(new WEdge(p5,fromNode,nodesLevelZero.get(toTitle)));
				}
			} else if (nodesLevelOne.containsKey(toTitle)) {
				if (!nodesLevelZero.containsKey(fromTitle)) {
					if (!nodesLevelOne.containsKey(fromTitle)) {
						if (!nodesLevelTwo.containsKey(fromTitle)) {
							putNode(fromNode,2);
							nodesLevelOne.get(toTitle).incLinks(2);
							fromNode.incBacklinks(1);
							allEdgesList.add(new WEdge(p5,fromNode,nodesLevelOne.get(toTitle)));
						} else {
							
						}
						
					} else {

					}
				} else {
				}
			} else if (nodesLevelTwo.containsKey(toTitle)) {
				if (!nodesLevelOne.containsKey(fromTitle)) {
					if (!nodesLevelTwo.containsKey(fromTitle)) {
						putNode(fromNode,2);
						nodesLevelTwo.get(toTitle).incLinks(2);
						fromNode.incBacklinks(2);
						allEdgesList.add(new WEdge(p5,fromNode,nodesLevelTwo.get(toTitle)));
					} else {
					}
				} else {
						
					}
			}
			if (!nodesLevelZero.containsKey(fromTitle) &&
					!nodesLevelOne.containsKey(fromTitle) &&
					!nodesLevelTwo.containsKey(fromTitle) &&
					!nodesLevelZero.containsKey(toTitle) &&
					!nodesLevelOne.containsKey(toTitle) &&
					!nodesLevelTwo.containsKey(toTitle) ) {
				putNode(fromNode,2);
				putNode(toNode,2);
				toNode.incBacklinks(2);
				fromNode.incLinks(2);
				allEdgesList.add(new WEdge(p5,fromNode,toNode));
				System.out.println("****************");
			}

		}
		//////LOOP handling!!!
		for (int i = 0; i < allNodesList.size(); i++) {
			if (maxLinkCount < allNodesList.get(i).getLinksCount(3)) maxLinkCount =allNodesList.get(i).getLinksCount(3);
		}

	}
	
	public void putNode(WNode theNode, int level) {
		switch (level) {
		case 0:
			nodesLevelZero.put(theNode.getTitle(), theNode);
			nodesLevelZeroList.add(theNode);
			allNodes.put(theNode.getTitle(), theNode);
			allNodesList.add(theNode);
			theNode.setLevel(WNode.LEVEL_ZERO);
			break;
		case 1:
			nodesLevelOne.put(theNode.getTitle(), theNode);
			nodesLevelOneList.add(theNode);
			allNodes.put(theNode.getTitle(), theNode);
			allNodesList.add(theNode);
			theNode.setLevel(WNode.LEVEL_ONE);
			break;
		case 2:
			nodesLevelTwo.put(theNode.getTitle(), theNode);
			nodesLevelTwoList.add(theNode);
			allNodes.put(theNode.getTitle(), theNode);
			allNodesList.add(theNode);
			theNode.setLevel(WNode.LEVEL_TWO);
			break;

		default:
			break;
		}
	}
}
